﻿using System;
using System.Threading;
using log4net;

namespace SharePoint.Orm.SiteBuilders {
    ///<summary>
    /// The main class that should be used for building the entities in a site.
    ///</summary>
    public class EntitiesBuilder {
        ///<summary>
        /// The class that holds the entities to be built.
        ///</summary>
        public virtual IBuildingContainer BuildingContainer { get; set; }

        ///<summary>
        /// The class that will build the fields for a site.
        ///</summary>
        public virtual IFieldBuilder FieldBuilder { get; set; }

        ///<summary>
        /// The context of the site in use.
        ///</summary>
        public virtual SPDataContext Ctx { get; set; }

        ///<summary>
        /// Logger for redirecting the output of the error messages.
        ///</summary>
        public virtual ILog Logger { get; set; }
        /// <summary>
        /// The group name for the builders.
        /// </summary>
        public virtual string GroupName { get; set; }
        ///<summary>
        /// The default constructor.
        ///</summary>
        public EntitiesBuilder() {
            
        }

        ///<summary>
        /// Constructor with the dependencies of Build
        ///</summary>
        ///<param name="ctx">The context of the site to build on.</param>
        ///<param name="buildingContainer">The container of entities to be built.</param>
        ///<param name="fieldBuilder">The container of the fields to be built.</param>
        /// <param name="groupName">The group name for the builders.</param>
        public EntitiesBuilder(SPDataContext ctx,IBuildingContainer buildingContainer,IFieldBuilder fieldBuilder,string groupName) {
            BuildingContainer = buildingContainer;
            FieldBuilder = fieldBuilder;
            Ctx = ctx;
            GroupName = groupName;
        }
        ///<summary>
        /// Builds all of the fields in the field builder and builds all of the entities in the building container.
        ///</summary>
        ///<exception cref="ArgumentNullException">BuildingContainer, FieldBuilder and Ctx must be set before calling Build</exception>
        public virtual void Build() {
            if(FieldBuilder == null) throw new ArgumentNullException("FieldBuilder must be set before calling Build",new Exception());
            if(BuildingContainer == null) throw new ArgumentNullException("BuildingContainer must be set before calling Build",new Exception());
            if(Ctx == null) throw new ArgumentNullException("Ctx must be set before calling Build",new Exception());
            if (GroupName == null) throw new ArgumentNullException("Group name must be set before calling Build", new Exception());
            using (BuilderContext builderContext = BuilderContext.CreateBuilderContext(Ctx, FieldBuilder, BuildingContainer,GroupName)) {
                try {
                    SiteBuilders.FieldBuilder.Site = Ctx.Site;
                    SiteBuilders.FieldBuilder.GroupName = GroupName;
                    FieldLookupBuilder.GroupName = GroupName;
                    FieldLookupBuilder.Site = Ctx.Site;
                    FieldBuilder.Build(Ctx);
                    builderContext.InstantiateBuilders();
                    builderContext.RunBuilders();
                } catch (Exception e) {
                    if (Logger != null)
                        Logger.Fatal(e);
                } finally {
                    EntityBuilderBase.CleanUpStaticResources();
                }
            }
        }
    }
}
